/**
 * Copyright [2012-2013] [Guðmundur Björn Birkisson]
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. Copyright [2012-2013] [Guðmundur Björn Birkisson]
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * ---------------------------------------------------------------------------
 * 
 * Class name:  MapEditorRenderer
 * 
 * Description of class:
 * 
 * Class that renders the map for MapEditor.
 * 
 */

package karel.editors.mapeditor;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import karel.gamelogic.world.KarelMap;
import karel.gamelogic.world.KarelRobot;
import karel.gamelogic.world.Tile;
import karel.graphics.BufferedRenderer;
import karel.util.FontLoader;

public class MapEditorRenderer extends javax.swing.JPanel {

    private KarelMap karelMap;
    private KarelRobot karelRobot;
    private int tileSize;
    private int offsetx;
    private int offsety;
    
    private Image robotImage;
    private Image rockImage1;
    private Image rockImage2;
    private Image rockImage3;
    private Font rendererFont;
    
    /**
     * Simple constructor.
     */
    public MapEditorRenderer() {
        initComponents();
        rendererFont = FontLoader.getDefaultFont(Font.BOLD, 20);
        try {
            robotImage = ImageIO.read(getClass().getResource("/images/robot.png"));
            rockImage1 = ImageIO.read(getClass().getResource("/images/rock1.png"));
            rockImage2 = ImageIO.read(getClass().getResource("/images/rock2.png"));
            rockImage3 = ImageIO.read(getClass().getResource("/images/rock3.png"));
        } catch (IOException ex) {
            Logger.getLogger(BufferedRenderer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    /**
     * Sets the map that should be rendered.
     * @param karelMap 
     */
    public void setMap(KarelMap karelMap) {
        this.karelMap = karelMap;
        calcTileSizeAndOffset();
    }
    
    /**
     * Sets the Robot that should be rendered.
     * @param karelRobot 
     */
    public void setKarelRobot(KarelRobot karelRobot) {
        this.karelRobot = karelRobot;
    }
    
    /**
     * Calculates tile size and map offset with regards to map and canvas size.
     */
    public void calcTileSizeAndOffset() {
        if (karelMap == null) {
            return;
        }
        tileSize = Math.min(getSize().width / karelMap.getWidth(), getSize().height / karelMap.getHeight());
        offsetx = (getSize().width - tileSize * karelMap.getWidth()) / 2;
        offsety = (getSize().height - tileSize * karelMap.getHeight()) / 2;
    }
    
    /**
     * Returns Point on map (in map coords). If position of evt not on map
     * it returns Point(-1,-1);
     * @param evt
     * @return 
     */
    public Point mouseClicked(java.awt.event.MouseEvent evt) {
        if(karelMap != null) {
            int x = evt.getX();
            int y = evt.getY();

            if(x < offsetx || y < offsety || x > (offsetx+tileSize*karelMap.WIDTH) || y > (offsety+tileSize*karelMap.HEIGHT)) {
                return new Point(-1, -1);
            }

            return new Point((x-offsetx)/tileSize,(y-offsety)/tileSize);
        }
        return new Point(-1, -1);
    }
    
    /**
     * Renders the world.
     * @param g 
     */
    @Override
    public void paintComponent(Graphics g) {
        g.setColor(new Color(212, 208, 200));
        g.fillRect(0, 0, getSize().width, getSize().height);
        ((Graphics2D)g).translate(offsetx, offsety);
        if(karelMap != null) {
            renderMap((Graphics2D)g, karelMap, tileSize);
            renderRocks((Graphics2D)g, karelMap, tileSize);
        }
        if(karelRobot != null) {
            renderRobot((Graphics2D)g, karelRobot, tileSize);
        }
    }
    
    /**
     * Renders the map.
     * @param g
     * @param map
     * @param tileSize 
     */
    private void renderMap(Graphics2D g, KarelMap map, int tileSize) {
        for (int x = 0; x < map.getWidth(); x++) {
            for (int y = 0; y < map.getHeight(); y++) {

                g.setColor(Tile.getColor(Tile.Type.CLEAR));
                if (map.isType(x, y, Tile.Type.BLOCKED)) {
                    g.setColor(Tile.getColor(Tile.Type.BLOCKED));
                } else if (map.isType(x, y, Tile.Type.EXIT)) {
                    g.setColor(Tile.getColor(Tile.Type.EXIT));
                }

                // draw the rectangle with a dark outline
                g.fillRect(x * tileSize, y * tileSize, tileSize, tileSize);
                g.setColor(g.getColor().darker());
                g.drawRect(x * tileSize, y * tileSize, tileSize, tileSize);
            }
        }

    }
    
    /**
     * Renders rocks on the map.
     * @param g
     * @param map
     * @param tileSize 
     */
    private void renderRocks(Graphics2D g, KarelMap map, int tileSize) {
        g.setFont(rendererFont);
        for (int x = 0; x < map.getWidth(); x++) {
            for (int y = 0; y < map.getHeight(); y++) {
                if (map.isType(x, y, Tile.Type.ROCK)) {
                    int rocks = map.getNumberOfRocks(x, y);
                    switch (rocks) {
                        case 1:
                            g.drawImage(rockImage1, x * tileSize, y * tileSize, tileSize, tileSize, null);
                            break;
                        case 2:
                            g.drawImage(rockImage2, x * tileSize, y * tileSize, tileSize, tileSize, null);
                            break;
                        case 3:
                            g.drawImage(rockImage3, x * tileSize, y * tileSize, tileSize, tileSize, null);
                            break;
                        default:
                            String str = Integer.toString(map.getNumberOfRocks(x, y));
                            g.setColor(new Color(0.0f, 0.0f, 0.3f));
                            g.drawImage(rockImage3, x * tileSize, y * tileSize, tileSize, tileSize, null);
                            g.drawString(str, (x + 1) * tileSize - g.getFontMetrics(rendererFont).stringWidth(str) - 5, (y + 1) * tileSize - 5);
                    }
                }
            }
        }
    }
    
    /**
     * Renders the robot on the map.
     * @param g
     * @param robot
     * @param tileSize 
     */
    private void renderRobot(Graphics2D g, KarelRobot robot, int tileSize) {
        int translationx = (int) (tileSize * robot.postition.getX()) + tileSize / 2 + 1;
        int translationy = (int) (tileSize * robot.postition.getY()) + tileSize / 2 + 1;
        double rotation = robot.direction;

        g.translate(translationx, translationy);
        g.rotate(rotation);
        g.drawImage(robotImage, -tileSize / 2, -tileSize / 2, tileSize, tileSize, null);
    }
    

    /*
     * Here below is auto generated code from NetBeans IDE 7.2.1
     */
    
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        addComponentListener(new java.awt.event.ComponentAdapter() {
            public void componentResized(java.awt.event.ComponentEvent evt) {
                formComponentResized(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 300, Short.MAX_VALUE)
        );
    }// </editor-fold>//GEN-END:initComponents

    private void formComponentResized(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_formComponentResized
        calcTileSizeAndOffset();
        repaint();
    }//GEN-LAST:event_formComponentResized

    // Variables declaration - do not modify//GEN-BEGIN:variables
    // End of variables declaration//GEN-END:variables
}
